
// <copyright file="ItemLockSafeEnumerable.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   The item lock safe enumerable.
// </summary>

namespace SubhadraSolutions.Sharp.Utils.Collections.Concurrent
{
    using System.Collections;
    using System.Collections.Generic;
    using System.Threading;

    /// <summary>
    /// The item lock safe enumerable.
    /// </summary>
    /// <typeparam name="T">
    /// </typeparam>
    public sealed class ItemLockSafeEnumerable<T> : IEnumerable<T>
        where T : class
    {
        #region Fields

        /// <summary>
        /// The enumerable.
        /// </summary>
        private readonly IEnumerable<T> enumerable;

        #endregion Fields

        #region Constructors and Finalizers

        /// <summary>
        /// Initializes a new instance of the <see cref="ItemLockSafeEnumerable{T}"/> class.
        /// </summary>
        /// <param name="enumerable">
        /// The enumerable.
        /// </param>
        public ItemLockSafeEnumerable(IEnumerable<T> enumerable)
        {
            this.enumerable = enumerable;
        }

        #endregion Constructors and Finalizers

        #region Public Methods and Operators

        /// <summary>
        /// The get enumerator.
        /// </summary>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        public IEnumerator<T> GetEnumerator()
        {
            return this.GetEnumeratorCore();
        }

        #endregion Public Methods and Operators

        #region Explicit Interface Methods

        /// <summary>
        /// The get enumerator.
        /// </summary>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumeratorCore();
        }

        #endregion Explicit Interface Methods

        #region Methods

        /// <summary>
        /// The get enumerator.
        /// </summary>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        private IEnumerator<T> GetEnumeratorCore()
        {
            return new ItemLockSafeEnumerator(this.enumerable.GetEnumerator());
        }

        #endregion Methods

        /// <summary>
        /// The item lock safe enumerator.
        /// </summary>
        private sealed class ItemLockSafeEnumerator : AbstractDisposable, IEnumerator<T>
        {
            #region Fields

            /// <summary>
            /// The enumerator.
            /// </summary>
            private readonly IEnumerator<T> enumerator;

            /// <summary>
            /// The previous.
            /// </summary>
            private readonly T previous = null;

            #endregion Fields

            #region Constructors and Finalizers

            /// <summary>
            /// Initializes a new instance of the <see cref="ItemLockSafeEnumerator"/> class.
            /// </summary>
            /// <param name="enumerator">
            /// The enumerator.
            /// </param>
            public ItemLockSafeEnumerator(IEnumerator<T> enumerator)
            {
                this.enumerator = enumerator;
            }

            /// <summary>
            /// Finalizes an instance of the <see cref="ItemLockSafeEnumerator"/> class.
            /// </summary>
            ~ItemLockSafeEnumerator()
            {
                this.Dispose(false);
            }

            #endregion Constructors and Finalizers

            #region Explicit Interface Properties

            /// <summary>
            /// Gets the current.
            /// </summary>
            object IEnumerator.Current
            {
                get
                {
                    return this.enumerator.Current;
                }
            }

            /// <summary>
            /// Gets the current.
            /// </summary>
            T IEnumerator<T>.Current
            {
                get
                {
                    return this.enumerator.Current;
                }
            }

            #endregion Explicit Interface Properties

            #region Public Methods and Operators

            /// <summary>
            /// The move next.
            /// </summary>
            /// <returns>
            /// The <see cref="bool"/>.
            /// </returns>
            public bool MoveNext()
            {
                bool canMove = this.enumerator.MoveNext();
                if (this.previous != null)
                {
                    Monitor.Exit(this.previous);
                }

                if (canMove)
                {
                    Monitor.Enter(this.enumerator.Current);
                }

                return canMove;
            }

            /// <summary>
            /// The reset.
            /// </summary>
            public void Reset()
            {
                this.enumerator.Reset();
            }

            #endregion Public Methods and Operators

            #region Methods

            /// <summary>
            /// The dispose.
            /// </summary>
            /// <param name="disposing">
            /// The disposing.
            /// </param>
            protected override void Dispose(bool disposing)
            {
                if (this.enumerator.Current != null)
                {
                    Monitor.Exit(this.enumerator.Current);
                }

                this.enumerator.Dispose();
            }

            #endregion Methods
        }
    }
}